﻿using Autofac;
using Autofac.Extras.DynamicProxy;
using FreeDream.Common;
using FreeDream.Model;
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace FreeDream.Infrastructure
{
    public class AutofacModuleRegister : Autofac.Module
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(AutofacModuleRegister));

        protected override void Load(ContainerBuilder builder)
        {
            var basePath = AppContext.BaseDirectory;
            //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();

            #region Aop

            ////// AOP 开关，如果想要打开指定的功能，只需要在 appsettigns.json 对应对应 true 就行。
            var cacheType = new List<Type>();
            //if (AppSettings.App(new string[] { "AppSettings", "RedisCachingAOP", "Enabled" }).ObjToBool())
            //{
            //    builder.RegisterType<DnRedisCacheAOP>();
            //    cacheType.Add(typeof(DnRedisCacheAOP));
            //}
            ////if (Appsettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
            ////{
            ////    builder.RegisterType<DnCacheAOP>();
            ////    cacheType.Add(typeof(DnCacheAOP));
            ////}
            ////if (Appsettings.app(new string[] { "AppSettings", "TranAOP", "Enabled" }).ObjToBool())
            ////{
            ////    builder.RegisterType<BlogTranAOP>();
            ////    cacheType.Add(typeof(BlogTranAOP));
            ////}
            //if (AppSettings.App(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool())
            //{
            //    builder.RegisterType<DnLogAOP>();   //可以直接替换其他拦截器！一定要把拦截器进行注册
            //    cacheType.Add(typeof(DnLogAOP));
            //}

            #endregion

            //builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>)).InstancePerDependency();//注册仓储

            //Assembly.LoadFile只载入相应的dll文件，比如Assembly.LoadFile("a.dll")，则载入a.dll，假如a.dll中引用了b.dll的话，b.dll并不会被载入。
            //Assembly.LoadFrom则不一样，它会载入dll文件及其引用的其他dll，比如上面的例子，b.dll也会被载入。
            //Assembly.LoadFrom(程序集的文件路径，包括扩展名)，而Assembly.Load（程序集名称,而不是文件名）

            //.EnableInterfaceInterceptors()//对目标类型启用接口拦截。拦截器将被确定，通过在类或接口上截取属性, 或添加 InterceptedBy(),
            //.InterceptedBy(typeof(BlogLogAOP));//允许将拦截器服务的列表分配给注册。说人话就是，将拦截器添加到要注入容器的接口或者类之上。

            //* 筛选出对应条件的接口
            //* IsAssignableFrom：返回true的条件：是否直接或间接实现了IDependency
            //* IsAbstract：是否为抽象类
            //* AsImplementedInterfaces：以接口的形式注册

            //InstancePerLifetimeScope：同一个Lifetime生成的对象是同一个实例
            //SingleInstance：单例模式，每次调用，都会使用同一个实例化的对象；每次都用同一个对象；
            //InstancePerDependency：默认模式，每次调用，都会重新实例化对象；每次请求都创建一个新的对象；

            #region 带有接口层的服务注入

            #region Assembly.LoadFrom方式获取文件

            //DataPlatform.Service
            //Assembly.LoadFrom 获取 Service.dll 程序集服务，并注册

            var servicesDllFile = Path.Combine(basePath, "FreeDream.Service.dll");
            if (!File.Exists(servicesDllFile))
            {
                var msg = "service.dll 丢失，因为项目解耦了，所以需要先F6编译，再F5运行，请检查 bin 文件夹，并拷贝。";
                log.Error(msg);
                throw new Exception(msg);
            }

            var assemblysServices = Assembly.LoadFrom(servicesDllFile);
            //builder.RegisterAssemblyTypes(assemblysServices).Where(m => m.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();

            builder.RegisterAssemblyTypes(assemblysServices)
                .AsImplementedInterfaces()
                .InstancePerDependency()
                .PropertiesAutowired()
                .EnableInterfaceInterceptors();       //引用Autofac.Extras.DynamicProxy;
                                                      //.InterceptedBy(cacheType.ToArray()); //允许将拦截器服务的列表分配给注册。

            //Assembly.LoadFrom 获取 Repository.dll 程序集服务，并注册
            var repositoryDllFile = Path.Combine(basePath, "FreeDream.Repository.dll");
            if (!File.Exists(servicesDllFile))
            {
                var msg = "Repository.dll丢失，因为项目解耦了，所以需要先F6编译，再F5运行，请检查 bin 文件夹，并拷贝。";
                log.Error(msg);
                throw new Exception(msg);
            }

            var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
            builder.RegisterAssemblyTypes(assemblysRepository)
                .AsImplementedInterfaces()
                .InstancePerDependency()
                .PropertiesAutowired()
                .EnableInterfaceInterceptors();

            //builder.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces().InstancePerLifetimeScope();
            //builder.RegisterAssemblyTypes(Assembly.Load(Assembly.GetExecutingAssembly().GetName())).AsImplementedInterfaces();

            #endregion

            #region Assembly.Load方式获取文件

            ////Assembly.Load
            //var assemblyService = Assembly.Load("DataPlatform.Service");
            //builder.RegisterAssemblyTypes(assemblyService).Where(m => m.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
            ////Assembly.Load
            //var assemblyRes = Assembly.Load(repositoryDllFile);
            //builder.RegisterAssemblyTypes(assemblyRes).AsImplementedInterfaces().InstancePerLifetimeScope();
            ////builder.RegisterAssemblyTypes(Assembly.Load(Assembly.GetExecutingAssembly().GetName())).AsImplementedInterfaces();

            #endregion

            #region 注册泛型

            //builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>)).InstancePerDependency();//注册仓储
            //builder.RegisterGeneric(typeof(BaseServices<>)).As(typeof(IBaseServices<>)).InstancePerDependency();//注册服务

            //builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork))
            //    .AsImplementedInterfaces()
            //    .InstancePerLifetimeScope()
            //    .PropertiesAutowired();

            #endregion

            #endregion

            #region 没有接口层的服务层注入

            //因为没有接口层，所以不能实现解耦，只能用 Load 方法。
            //注意如果使用没有接口的服务，并想对其使用 AOP 拦截，就必须设置为虚方法
            //var assemblysServicesNoInterfaces = Assembly.Load("DataPlatform.Services");
            //builder.RegisterAssemblyTypes(assemblysServicesNoInterfaces);

            #endregion

            #region 没有接口的单独类，启用class代理拦截

            builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love)))
                .EnableClassInterceptors()
                .InterceptedBy(cacheType.ToArray());

            #endregion

            #region 单独注册一个含有接口的类，启用interface代理拦截

            //不用虚方法
            //builder.RegisterType<AopService>().As<IAopService>()
            //   .AsImplementedInterfaces()
            //   .EnableInterfaceInterceptors()
            //   .InterceptedBy(typeof(BlogCacheAOP));

            #endregion

            #region 针对某一层的指定类的指定方法进行操作

            //配合Attribute就可以只拦截相应的方法了。因为拦截器里面是根据Attribute进行相应判断的！！
            //builder.RegisterAssemblyTypes(assembly)
            //     .Where(type => typeof(IQCaching).IsAssignableFrom(type) && !type.GetTypeInfo().IsAbstract).AsImplementedInterfaces()
            //     .InstancePerLifetimeScope()
            //     .EnableInterfaceInterceptors()
            //     .InterceptedBy(typeof(QCachingInterceptor));

            #endregion
        }


        #region Load另外的注释

        //protected override void Load(ContainerBuilder builder)
        //{
        //    // 获取所有创建的项目Lib
        //    var libs = DependencyContext.Default
        //    .CompileLibraries
        //    .Where(x => !x.Serviceable && x.Type == "project").ToList();

        //    // 将lib转成Assembly
        //    List<Assembly> assemblies = new();
        //    foreach (var lib in libs)
        //    {
        //        assemblies.Add(AssemblyLoadContext.Default
        //        .LoadFromAssemblyName(new AssemblyName(lib.Name)));
        //    }

        //    // 反射获取其中所有的被接口修饰的类型，并区分生命周期
        //    builder.RegisterAssemblyTypes(assemblies.ToArray())
        //        .Where(t => t.IsAssignableTo<IocTagScope>() && !t.IsAbstract)
        //        .AsSelf()
        //        .AsImplementedInterfaces()
        //        .InstancePerLifetimeScope()
        //        .PropertiesAutowired();

        //    builder.RegisterAssemblyTypes(assemblies.ToArray())
        //        .Where(t => t.IsAssignableTo<IocTagSington>() && !t.IsAbstract)
        //        .AsSelf()
        //        .AsImplementedInterfaces()
        //        .SingleInstance()
        //        .PropertiesAutowired();

        //    builder.RegisterAssemblyTypes(assemblies.ToArray())
        //        .Where(t => t.IsAssignableTo<IocTagTransient>() && !t.IsAbstract)
        //        .AsSelf()
        //        .AsImplementedInterfaces()
        //        .PropertiesAutowired();

        //    builder.RegisterAssemblyTypes(assemblies.ToArray())
        //        .Where(t => t.IsAssignableTo<ControllerBase>() && !t.IsAbstract)
        //        .AsSelf()
        //        .PropertiesAutowired();
        //}

        //public interface IocTagScope
        //{

        //}

        #endregion
    }
}
